package ch.ethz.inf.shop.model.simpleDatabase.operators.tests;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import org.junit.Assert;
import org.junit.Test;

import ch.ethz.inf.shop.model.simpleDatabase.operators.GroupBy;
import ch.ethz.inf.shop.model.simpleDatabase.operators.GroupBy.AggregateFunction;
import ch.ethz.inf.shop.model.simpleDatabase.operators.Join;
import ch.ethz.inf.shop.model.simpleDatabase.operators.Operator;
import ch.ethz.inf.shop.model.simpleDatabase.operators.Scan;

public class TestGroupBy {

	/**
	 * select user_id, count(product_id) like_cnt from shop.like group by
	 * user_id;
	 */
	@Test
	public void GroupByUserCountLikesTest() {
		// mapping user_id to like_cnt
		Map<Integer, Integer> expectedTestResults = new HashMap<Integer, Integer>();
		expectedTestResults.put(1, 2);
		expectedTestResults.put(2, 3);
		Scan scan = new Scan(AllTests.ROOT_DIRECTORY + "/like.txt", "like");
		GroupBy groupBy = new GroupBy(scan, AggregateFunction.COUNT, "like.product_id", "like_cnt", "like.user_id");

		while (groupBy.moveNext()) {
			int expected = expectedTestResults.get(groupBy.current().getInt("like.user_id"));
			Assert.assertEquals(expected, groupBy.current().getInt("like_cnt"));
		}

	}

	/**
	 * select product_id, count(user_id) like_cnt from shop.like group by
	 * product_id;
	 */
	@Test
	public void GroupByProductCountLikesTest() {
		// mapping product_id to like_cnt
		Map<Integer, Integer> expectedTestResults = new HashMap<Integer, Integer>();
		expectedTestResults.put(1, 1);
		expectedTestResults.put(2, 1);
		expectedTestResults.put(12, 2);
		expectedTestResults.put(3, 1);
		Scan scan = new Scan(AllTests.ROOT_DIRECTORY + "/like.txt", "like");
		GroupBy groupBy = new GroupBy(scan, AggregateFunction.COUNT, "like.user_id", "like_cnt", "like.product_id");

		while (groupBy.moveNext()) {
			int currentProduct = groupBy.current().getInt("like.product_id");
			int expected = expectedTestResults.get(currentProduct);
			Assert.assertEquals(expected, groupBy.current().getInt("like_cnt"));
		}

	}

	/**
	 * select recipe_item.*, product.*, sum(price) price_sum from recipe_item,
	 * product where recipe_item.product=product.product_id group by
	 * recipe_item.recipe;
	 * 
	 * note: sum(price*amount) not working currently --> something must be done
	 * in project
	 */
	@Test
	public void GroupBySumRecipePrice() {
		// mapping recipe_id to summed price
		Map<Integer, BigDecimal> expectedTestResults = new HashMap<Integer, BigDecimal>();
		expectedTestResults.put(1, new BigDecimal("8.70"));
		expectedTestResults.put(2, new BigDecimal("7.80"));
		expectedTestResults.put(3, new BigDecimal("7.80"));
		expectedTestResults.put(4, new BigDecimal("14.80"));
		expectedTestResults.put(5, new BigDecimal("1002.39"));
		expectedTestResults.put(6, new BigDecimal("21.30"));
		expectedTestResults.put(7, new BigDecimal("19.60"));

		Operator leftOp = new Scan(AllTests.ROOT_DIRECTORY + "/recipe_item.txt", "recipe_item");
		Operator rightOp = new Scan(AllTests.ROOT_DIRECTORY + "/product.txt", "product");

		leftOp = new Join(leftOp, "recipe_item.product", rightOp, "product.product_id");
		GroupBy gb = new GroupBy(leftOp, AggregateFunction.SUM, "product.price", "price_sum", "recipe_item.recipe");

		while (gb.moveNext()) {
			BigDecimal expected = expectedTestResults.get(gb.current().getInt("recipe_item.recipe"));
			Assert.assertEquals(expected, gb.current().getBigDecimal("price_sum"));
		}
	}
}
